package com.ophiux.utils.parser.json;

import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;

import com.alibaba.fastjson.JSON;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.reflect.TypeToken;
import com.ophiux.utils.exception.OphiuxApiException;
import com.ophiux.utils.parser.EntityConverter;
import com.ophiux.utils.parser.IConvert;
import com.ophiux.utils.parser.Reader;
import com.ophiux.utils.parser.Writer;
import com.ophiux.utils.test.StuDto;

public class JsonConverter implements IConvert {

	private static Type typeToken = new TypeToken<TreeMap<String, Object>>(){}.getType();
    //解决gson  int变成double类型
    Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken<TreeMap<String, Object>>() {}.getType(),
            new JsonDeserializer<TreeMap<String, Object>>() {
                @Override
                public TreeMap<String, Object> deserialize(
                        JsonElement json, Type typeOfT,
                        JsonDeserializationContext context) throws JsonParseException {

                    TreeMap<String, Object> treeMap = new TreeMap<>();
                    JsonObject jsonObject = json.getAsJsonObject();
                    Set<Map.Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
                    for (Map.Entry<String, JsonElement> entry : entrySet) {
                        Object ot = entry.getValue();
                        if (ot instanceof JsonPrimitive) {
                            treeMap.put(entry.getKey(), ((JsonPrimitive) ot).getAsString());
                        } else {
                            treeMap.put(entry.getKey(), ot);
                        }
                    }
                    return treeMap;
                }
            }).create();

    @Override
    public <T> T toEntity(Class<T> clzz, String dataSource) throws OphiuxApiException {Map<?, ?> json = (Map<?, ?>) JSON.parse(dataSource);
		return buildEntityByJSON(json, clzz);
		//GSON 后面会出现1遍1.0
//    	return buildEntityByJSON(gson.fromJson(dataSource, typeToken), clzz);
    }
    

    public static void main(String[] args) throws OphiuxApiException {
        JsonConverter json = new JsonConverter();
        StuDto aaa = json.toEntity(StuDto.class, "{\"NAME\":\"1\",\"aaa\":\"bbb\"}");
        System.out.println(aaa.getName());
    }

	/**
	 * 把JSON格式的数据转换为对象。
	 * 
	 * @param <T>   泛型领域对象
	 * @param json  JSON格式的数据
	 * @param clazz 泛型领域类型
	 * @return 领域对象
	 * @throws TopException
	 */
	public <T> T buildEntityByJSON(final Map<?, ?> json, Class<T> clzz) throws OphiuxApiException {
		Reader xmlReader = new Reader() {

			@Override
			public boolean isExistNode(String tagNames) {
				return json.containsKey(tagNames);
			}

			@Override
			public Object getNodeValue(String tagNames) {
				return json.get(tagNames);
			}

			@Override
			public Object getNodeObject(String tagName, Class<?> subType) throws OphiuxApiException {
				Object tmp = json.get(tagName);
				if (tmp instanceof Map<?, ?>) {
					Map<?, ?> map = (Map<?, ?>) tmp;
					return buildEntityByJSON(map, subType);
				} else {
					return null;
				}
			}

			@Override
			public List<?> getNodeListObject(String parentName, String tagNames, Class<?> subType)
					throws OphiuxApiException {
				List<Object> listObjs = null;

				Object listTmp = json.get(parentName);
				if (listTmp instanceof Map<?, ?>) {
					Map<?, ?> jsonMap = (Map<?, ?>) listTmp;
					Object itemTmp = jsonMap.get(tagNames);
					if (itemTmp == null && parentName != null) {
						String listNameStr = parentName.toString();
						itemTmp = jsonMap.get(listNameStr.substring(0, listNameStr.length() - 1));
					}
					if (itemTmp instanceof List<?>) {
						listObjs = getListObjectsInner(subType, itemTmp);
					}
				} else if (listTmp instanceof List<?>) {
					listObjs = getListObjectsInner(subType, listTmp);
				}

				return listObjs;
			}

			private List<Object> getListObjectsInner(Class<?> subType, Object itemTmp) throws OphiuxApiException {
				List<Object> listObjs;
				listObjs = new ArrayList<Object>();
				List<?> tmpList = (List<?>) itemTmp;
				for (Object subTmp : tmpList) {
					Object obj = null;
					if (String.class.isAssignableFrom(subType)) {
						obj = subTmp;
					} else if (Long.class.isAssignableFrom(subType)) {
						obj = subTmp;
					} else if (Integer.class.isAssignableFrom(subType)) {
						obj = subTmp;
					} else if (Boolean.class.isAssignableFrom(subType)) {
						obj = subTmp;
					} else if (Date.class.isAssignableFrom(subType)) {
						DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
						try {
							obj = format.parse(String.valueOf(subTmp));
						} catch (ParseException e) {
							throw new OphiuxApiException(e);
						}
					} else if (subTmp instanceof Map<?, ?>) {// object
						Map<?, ?> subMap = (Map<?, ?>) subTmp;
						obj = buildEntityByJSON(subMap, subType);
					}

					if (obj != null) {
						listObjs.add(obj);
					}
				}
				return listObjs;
			}
		};
		return EntityConverter.convert(clzz, xmlReader);
	}

	@Override
	public <T> String entityToString(T obj) throws OphiuxApiException {
		return parseEntityToString(obj);
	}

	public <T> String parseEntityToString(T obj) throws OphiuxApiException {
		String targetStr = "";
		Writer writer = new Writer() {

			@Override
			public String writerFromString(Object value, String nodeName) throws OphiuxApiException {
				String str = "";
				if (value == null || value.equals("null")) {
					value = "";
				}
				str += "\"" + nodeName + "\":\"" + value + "\",";
				return str;
			}

			@Override
			public String writerFromObject(Object obj, String nodeName) throws OphiuxApiException {
				String str = "";
				if (obj != null) {
					String objStr = parseEntityToString(obj);
					str += "\"" + nodeName + "\":" + objStr + ",";
				} else {
					str += "\"" + nodeName + "\":null,";
				}

				return str;
			}

			@Override
			public <T> String writerFromArray(List<T> valueList, String parentNodeName, String nodeName)
					throws OphiuxApiException {
				String str = "";
				String listStr = "";
				if (valueList != null && valueList.size() != 0) {
					for (T obj : valueList) {
						String objStr = "";
						objStr += parseEntityToString(obj) + ",";
						listStr += objStr;
					}
				}
				if (listStr.length() > 0) {
					listStr = listStr.substring(0, listStr.length() - 1);
					// 为了防止最后截取,号把中括号截取掉，在这里后面加了个,号
					str += "\"" + parentNodeName + "\":[" + listStr + "],";
				} else {
					str += "\"" + parentNodeName + "\":[],";
				}

				return str;
			}
		};

		targetStr = EntityConverter.writerToString(obj, writer);
		if (targetStr.length() > 0) {
			targetStr = targetStr.substring(0, targetStr.length() - 1);
			targetStr = "{" + targetStr + "}";
		}
		return targetStr;
	}

	@Override
	public <T> SortedMap entityToMap(T obj) throws OphiuxApiException {
		// TODO Auto-generated method stub
		return null;
	}

}
